package security.security.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import security.security.ApiAccessDeniedHandler;
import security.security.CustomUnauthorizedEntryPoint;
import security.security.decide.CustomAccessDecisionManager;
import security.security.decide.SecuritySettings;
import security.security.login.CustomAuthenticationProvider;
import security.security.login.CustomUserDetailsService;
import security.security.login.LoginFailureHandler;
import security.security.login.LoginSuccessHandler;

@Configuration
@ConfigurationProperties("security-config")
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class CustomSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    private SecuritySettings securitySettings;
    @Autowired
    private CustomUserDetailsService customUserDetailsService;
    @Autowired
    private CustomUnauthorizedEntryPoint customUnauthorizedEntryPoint;
    @Autowired
    private ApiAccessDeniedHandler apiAccessDeniedHandler;


    // 解决AuthenticationManager不能自动注入问题
//    @Bean(name = BeanIds.AUTHENTICATION_MANAGER)
//    @Override
//    public AuthenticationManager authenticationManagerBean() throws Exception {
//        return super.authenticationManagerBean();
//    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        // 由于使用的是JWT，这里不需要csrf
        httpSecurity.csrf().disable();
        httpSecurity.formLogin()
                .loginProcessingUrl("/login")
                .successHandler(loginSuccessHandler())
                .failureHandler(loginFailureHandler());
        // 异常处理
        httpSecurity.exceptionHandling()
                .authenticationEntryPoint(customUnauthorizedEntryPoint)
                .accessDeniedHandler(apiAccessDeniedHandler);
        // 基于token，所以不需要session
        httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // 请求鉴权
        httpSecurity.authorizeRequests().anyRequest().authenticated();
        // 决策管理器
        httpSecurity.authorizeRequests().accessDecisionManager(accessDecisionManager());
        // 禁用缓存
        httpSecurity.headers().cacheControl().disable();
        // 没有授权之前检查用户状态（锁定，可用，账号过期，凭证过期）
    }

    @Bean
    public CustomAccessDecisionManager accessDecisionManager() {
        return new CustomAccessDecisionManager(securitySettings, customUserDetailsService);
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        return new CustomAuthenticationProvider(customUserDetailsService, bCryptPasswordEncoder());
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public LoginSuccessHandler loginSuccessHandler(){
        return new LoginSuccessHandler();
    }

    @Bean
    public LoginFailureHandler loginFailureHandler(){
        return new LoginFailureHandler();
    }

}
